package com.geor.gcv.core.mat;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.opencv.core.Mat;

import com.geor.gcv.core.model.Area;

/**
 * X和Y轴的投影切分
 * 
 * 
 * @author geor.yuli
 *
 */
public class CellChipperAxisImpl implements CellChipper {

	@Override
	public List<Area> execute(Mat mat) throws Exception {
		
		List<Area> areas = new ArrayList<Area>();
		List<Integer> counter = new ArrayList<Integer>(mat.cols());
		// 投影到X轴
		for (int i = 0; i < mat.cols(); i++) {
			int num = 0;
			for (int j = 0; j < mat.rows(); j++) {
				double[] matD = mat.get(j, i);
				if (null != matD && matD[0] == 255d) {
					num++;
				}
			}
			counter.add(num);
		}
		// 切分
		boolean inArea = false;
		for (int i = 0; i < counter.size(); i++) {
			// 起始
			if (!inArea && counter.get(i) > 1) {
				Area area = new Area();
				area.setX(i);
				areas.add(area);
				inArea = true;
			}
			// 结束
			if (inArea && (counter.get(i) <= 1 || i >= counter.size() - 1)) {
				Area area = areas.get(areas.size() - 1);
				area.setWidth(i - area.getX() + 1);
				inArea = false;
			}
		}
		// 区域上下
		for (Area area : areas) {
			int top = findTop(mat, area.getX(), (area.getX() + area.getWidth()));
			int btm = findBottom(mat, area.getX(), (area.getX() + area.getWidth()));
			area.setY(top);
			area.setHeight(btm - top + 1);
		}
		
		return areas;
	}
	
	/**
	 * 找到Mat峰顶Y坐标, 去除顶上的点干扰
	 * 
	 * @param mat
	 * @return
	 */
	private int findTop(Mat mat, int left, int right) {
		int[] horizons = new int[mat.rows()];
		for (int i = 0; i < mat.rows(); i++) {
			int total = 0;
			for (int j = left; j < right; j++) {
				if (mat.get(i, j)[0] == 255d) {
					total++;
				}
			}
			horizons[i] = total;
		}
		int index = 0;
		int height = 0;
		for (int i = 0; i < horizons.length; i++) {
			if (horizons[i] > 0) {
				height++;
				index = i;
			} else {
				height = 0;
			}
			if (height >= Math.min(mat.rows(), 1)) {
				return index + 1 - height;
			}
		}
		return 0;
	}

	/**
	 * 找到一个区间的底部
	 * 
	 * @param mat
	 * @param left
	 * @param right
	 * @return
	 */
	private int findBottom(Mat mat, int left, int right) {
		int[] horizons = new int[mat.rows()];
		for (int i = 0; i < mat.rows(); i++) {
			int total = 0;
			for (int j = left; j < right; j++) {
				if (mat.get(i, j)[0] == 255) {
					total++;
				}
			}
			horizons[i] = total;
		}
		int index = 0;
		int height = 0;
		for (int i = horizons.length - 1; i > 0; i--) {
			if (horizons[i] > 0) {
				height++;
				index = i;
			} else {
				height = 0;
			}
			if (height >= Math.min(mat.rows(), 1)) {
				return index + height;
			}
		}
		return mat.rows() - 1;
	}

	@Override
	public void setParams(Properties properties) {

	}

}
